package repositories

import (
	"context"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"gorm.io/gorm"
)

type HostRepository interface {
	Create(ctx context.Context, host *models.HostResource) error
	DeleteAll(ctx context.Context) error
	FindByHost(ctx context.Context, host string) (*models.HostResource, error)
	FindAll(ctx context.Context) ([]*models.HostResource, error)
	FindByID(ctx context.Context, id uint64) (*models.HostResource, error)
	FindByIP(ctx context.Context, ip string) (*models.HostResource, error)
	FindByEnvIDAndGroupAndDCAndNameAndLikeName(ctx context.Context, envID uint64, group, dc, name, query string, pageNum, pageSize uint64) ([]*models.HostResource, int64, error)
}

type hostRepository struct {
	db *gorm.DB
}

func NewHostRepository(db *gorm.DB) HostRepository {
	return &hostRepository{
		db: db,
	}
}

func (h *hostRepository) Create(ctx context.Context, host *models.HostResource) error {
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).Create(host).Error; err != nil {
		return errors.Wrap(err, "create host error")
	}
	return nil
}

func (h *hostRepository) DeleteAll(ctx context.Context) error {
	host := new(models.HostResource)
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).Delete(host, "1=1").Error; err != nil {
		return errors.Wrap(err, "delete host error")
	}
	return nil
}

func (h *hostRepository) FindByHost(ctx context.Context, host string) (*models.HostResource, error) {
	var result = new(models.HostResource)
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).Where("hostname = ?", host).First(result).Error; err != nil {
		return nil, errors.Wrap(err, "find host by hostname error")
	}
	return result, nil
}

func (h *hostRepository) FindAll(ctx context.Context) ([]*models.HostResource, error) {
	var hosts []*models.HostResource
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).Find(&hosts).Error; err != nil {
		return nil, errors.Wrap(err, "find all error")
	}
	return hosts, nil
}

func (h *hostRepository) FindByID(ctx context.Context, id uint64) (*models.HostResource, error) {
	host := new(models.HostResource)
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).First(host, "id = ?", id).Error; err != nil {
		return nil, errors.Wrap(err, "find all error")
	}
	return host, nil
}
func (h *hostRepository) FindByIP(ctx context.Context, ip string) (*models.HostResource, error) {
	host := new(models.HostResource)
	if err := h.db.WithContext(ctx).Table(models.HostResourceTableName).First(host, "ip = ?", ip).Error; err != nil {
		return nil, errors.Wrap(err, "find all error")
	}
	return host, nil
}

func (h *hostRepository) FindByEnvIDAndGroupAndDCAndNameAndLikeName(ctx context.Context, envID uint64, group, dc, name, query string, pageNum, pageSize uint64) ([]*models.HostResource, int64, error) {
	result := make([]*models.HostResource, 0)
	totalCount := int64(0)

	db := h.db.WithContext(ctx).Table(models.HostResourceTableName)

	if envID != 0 {
		db = db.Where("env_id = ?", envID)
	}

	if group != "" {
		db = db.Where("`group` = ?", group)
	}

	if dc != "" {
		db = db.Where("dc = ?", dc)
	}

	if name != "" {
		db = db.Where("hostname = ?", name)
	}

	if query != "" {
		db = db.Where("hostname like ? or ip like ? or ip_outside like ?", "%"+query+"%", "%"+query+"%", "%"+query+"%")
	}

	if err := db.
		Order("score,hostname").
		Count(&totalCount).
		Limit(int(pageSize)).
		Offset(int(pageSize * (pageNum - 1))).
		Scan(&result).Error; err != nil {
		return nil, 0, errors.Wrap(err, "find host error")
	}

	return result, totalCount, nil
}
